using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.UI;
using CodeStory.SmartUpload.WebControls;

namespace CodeStory.SmartUpload
{
	public class SmartData
	{
		private byte[] boundary;
		SmartBuffer smartBuffer;
		Thread parseThread;
		int contentLength = -1;
		Encoding contentEncoding = Encoding.ASCII;
		HttpApplication application;
		SmartUploadContext currentUploadContext = null;

		private SmartField currentField = null;
		int parsePosition = 0;
		int parseVirtualPosition = 0;

		public SmartUploadContext CurrentUploadContext {
			get {
				if (currentUploadContext == null) {
					currentUploadContext = SmartUploadContext.GetContext(Application.Context);
				}
				return currentUploadContext; }
		}

		public HttpApplication Application {
			get { return application; }
			set { application = value; }
		}


		public SmartData() {
			smartBuffer = new SmartBuffer(0x200000);
			//CurrentUploadContext.SmartProgress.Status = UploadStatus.Uploading;
		}

		public Encoding ContentEncoding {
			get { return contentEncoding; }
			set { contentEncoding = value; }
		}

		public int ContentLength {
			set {
				contentLength = value;
				CurrentUploadContext.SmartProgress.ContentLength = value;
			}
		}

		public SmartBuffer SmartBuffer {
			get { return smartBuffer; }
		}
		public byte[] Boundary {
			set { boundary = value; }
		}

		public void AppendBytes(byte[] buffer, int offset, int length) {
			lock (smartBuffer.SyncRoot) {
				smartBuffer.Append(buffer, offset, length);
				//LoggingService.Info("Append data buffer...");
			}
		}
		public Thread StartParseThread() {
			parseThread = new Thread(new ThreadStart(Parse));
			parseThread.Start();

			//LoggingService.Info("Thread Started...");
			return parseThread;
		}

		private int ParsePosition {
			get { return parsePosition; }
			set { parsePosition = value; }
		}

		private int ParseVirtualPosition {
			get { return parseVirtualPosition; }
			set { 
				parseVirtualPosition = value;
				CurrentUploadContext.SmartProgress.UploadedLength = value;
			}
		}
		private void IncreaseParsePosition(int step) {
			ParsePosition += step;
			ParseVirtualPosition += step;
		}
		private void DecreaseParsePosition(int step) {
			//LoggingService.Info("Decrease ParsePosition execute...");
			ParsePosition -= step;
		}
		private void Parse() {
			int boundarylength = boundary.Length;
			while (ParseVirtualPosition < contentLength) {
				if (smartBuffer[ParsePosition] == 13 && smartBuffer[ParsePosition + 1] == 10) {
					if (smartBuffer.Equals(ParsePosition - boundarylength, boundarylength, boundary)) {
						FlushDataInternal(currentField,true);
						IncreaseParsePosition(2);//Jump to next line
						currentField = AnalysisAttributes();
					}
				}
				if (currentField != null && ParsePosition - currentField.CurrentBufferPosition > 0x50000) {
					FlushDataInternal(currentField,false);
				}
				IncreaseParsePosition(1);
			}
			CurrentUploadContext.SmartProgress.Status = UploadStatus.Completed;
		}

		private void FlushDataInternal(SmartField field,bool closeField) {
			if (field == null) return;
			int flushDataLength = ParsePosition - boundary.Length - field.CurrentBufferPosition;
			if (!field.IsFile) return;
			//LoggingService.Info("Flush Data Internal execute...");
			lock (smartBuffer.SyncRoot) {
				byte[] data = smartBuffer.Remove(field.CurrentBufferPosition, flushDataLength);
				field.FlushData(data);
				DecreaseParsePosition(data.Length);
				field.CurrentBufferPosition -= data.Length;
			}
			if (closeField) {
				field.Close();
			}
		}

		private SmartField AnalysisAttributes() {
			int temp = ParsePosition;
			SmartField field = new SmartField();
			field.Application = application;
			while (true) {
				if (smartBuffer[temp] == 13 && smartBuffer[temp + 1] == 10) {
					byte[] line = smartBuffer.GetBytes(ParsePosition, temp - ParsePosition);
					string lineStr = ContentEncoding.GetString(line).ToLower();
					if (lineStr.StartsWith("content-disposition:")) {
						string[] parts = lineStr.Split(';');
						foreach (string p in parts) {
							int index = p.IndexOf("=");
							if (index < 0) continue;
							string n = p.Substring(0, index).Trim();
							string v = p.Substring(index + 1).Trim('\"', ' ');
							if (n == "name") {
								field.Name = v;
							} else if (n == "filename") {
								field.FileName = v;
							}
						}
					} else if (lineStr.StartsWith("content-type:")) {
						field.MimeType = lineStr.Substring(13).Trim();
					}
					IncreaseParsePosition(temp - ParsePosition);
					//Next line
					IncreaseParsePosition(2);
					if (smartBuffer[temp + 2] == 13 && smartBuffer[temp + 3] == 10) {
						IncreaseParsePosition(2);
						field.CurrentBufferPosition = ParsePosition;
						break;
					}
				}
				temp++;
			}
			return field;
		}

		internal void Abort() {
			try {
				parseThread.Abort();
				CurrentUploadContext.SmartProgress.Status = UploadStatus.UserAbort;
				if (currentField != null) {
					currentField.Abort();
				}
			} catch (ThreadAbortException){
			}
		}
	}
}
